home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <stream.h>
- #include <sys/types.h>
- #include <sys/time.h>
- #include "sw.h"
- #include "extern.h"
- #include "main.h"
- #include "sw_comm.h"
- #include "control.h"
- #include "display.h"
- #include "explode.h"
- #include "hud.h"
- #include "ship.h"
- #include "universe.h"
- #include "ship_regular.h"
- #include "sound.h"
- #include <Inventor/SoSensor.h>
-
- static SoOneShotSensor* goingIdle; // frameAdvance sensor
- static struct timeval timeStart, // to find time step
- timeEnd, // to find time step
- fpsStart; // start time to find fps
- static struct timezone tz;
-
- ShipObject* myShip; // pointer to my ship
- int buttonPressed[3]; // mouse button states
-
- // since we're using transparent stuff our Inventor callbacks get called
- // multiple times for each frame. I can't find a way to find out which
- // pass is being drawn from Inventor, so frameNumber will tell us when
- // we should actually draw the stars and hud. The number actually just
- // cycles from 0 to some small number (it's also used to calculate frames
- // per second).
- int frameNumber;
-
- // too be sure we don't advance the frame until something has actually
- // been drawn, frameDrawn is set when the stars are drawn.
- int frameDrawn;
-
- // view screen positions and visibility of every object
- ObjectView playerView[MAXPLAYERS][MAXMISSILES+1];
- ObjectView asteroidView[MAXASTEROIDS];
- ObjectView flagView[NUMTEAMS];
- ObjectView missileLock;
- int wasFlagCaptured; // TRUE if my flag just captured
-
- // bunch 'o useful stuff here
- static ShipObject* shipList[MAXPLAYERS]; // list of all ships
- static ShipObject* targetList[MAXPLAYERS]; // list of all targets
- static int targetPlayer[MAXPLAYERS];// target player number
- static int numPlayers; // number of players
- static int numTargets; // number of available targets
- static int target; // current target number
- static Weapon weaponState; // current weapon
- static int fps; // current frames per second
- static int showFps = FALSE; // TRUE if fps displayed
- static int rangeState; // current range setting
- static int done = FALSE; // quit flag
- static int paused = FALSE; // paused flag
- static int pausedOnIconify = FALSE;// paused due to iconified flag
- static XtIntervalId pausedTimeout;
- static SbVec2s viewSize; // view screen size
- static float cameraCotan; // -1.0/tan(camera angle)
- static float cameraAspect; // camera aspect ratio
- static SwServer* gameServer; // pointer to server
- static TeamInfo teamStatus[NUMTEAMS]; // team information
- static Active oldActive; // active state before pausing
-
- // radar ranges are stored here (in meters)
- #define NUMRADARRANGES 3
- static float range[NUMRADARRANGES] = { 1000.0, 4000.0, 10000.0 };
-
- static void pausedWakeup(XtPointer, XtIntervalId*)
- {
- // reset wakeup call
- pausedTimeout = XtAppAddTimeOut(SoXt::getAppContext(), 1000,
- pausedWakeup, 0);
-
- handleServerMessages();
- handleBroadcastMessages();
- sendBroadcast(myShip->shipInfo());
- }
-
- static void initializeSelf()
- {
- myShip->reset();
- if (wasFlagCaptured) {
- float* bp = basePosition(myShip->team());
- float p[3];
- do {
- p[0] = drand48() * 2.0 - 1.0;
- p[1] = drand48() * 2.0 - 1.0;
- p[2] = drand48() * 2.0 - 1.0;
- } while (p[0] * p[0] + p[1] * p[1] + p[2] * p[2] > 1.0);
- p[0] = bp[0] + 0.9 * BASERADIUS * p[0];
- p[1] = bp[1] + 0.9 * BASERADIUS * p[1];
- p[2] = bp[2] + 0.9 * BASERADIUS * p[2];
- myShip->position(SbVec3f(p));
- wasFlagCaptured = FALSE;
- }
- else {
- float p[3];
- do {
- p[0] = 0.8 * FIELDSIZE * (drand48() * 2.0 - 1.0);
- p[1] = 0.8 * FIELDSIZE * (drand48() * 2.0 - 1.0);
- p[2] = 0.8 * FIELDSIZE * (drand48() * 2.0 - 1.0);
- } while (hitAsteroid(p, 2.0*myShip->shipBound()) != -1);
- myShip->position(SbVec3f(p));
- }
- myShip->orientation(SbRotation(SbVec3f(drand48() * 2.0 - 1.0,
- drand48() * 2.0 - 1.0,
- drand48() * 2.0 - 1.0),
- 2.0 * M_PI * drand48()));
- }
-
- static void findTargets()
- {
- ShipObject* oldTarget = (target == -1) ? NULL : targetList[target];
- target = -1;
- numTargets = 0;
- if (myShip->active() == ObjectInactive || myShip->exploding()) return;
- for (int i = 1; i < numPlayers; i++) {
- if (shipList[i]->active() == ObjectActive && !shipList[i]->exploding()) {
- targetList[numTargets] = shipList[i];
- targetPlayer[numTargets] = i;
- if (targetList[numTargets] == oldTarget) target = numTargets;
- numTargets++;
- }
- }
- if (oldTarget && target == -1) targetChanged();
- }
-
- static int computeVisibility(ObjectView& ov, float r)
- {
- if (ov.lp[2] >= 0.0) {
- ov.visible = FALSE;
- return FALSE;
- }
- float s = 0.5 * cameraCotan / ov.lp[2];
- ov.p[0] = (short)(0.5 + (float)viewSize[0] * (s * ov.lp[0]/cameraAspect+0.5));
- ov.p[1] = (short)(0.5 + (float)viewSize[1] * (s * ov.lp[1] + 0.5));
- ov.r = (short)(0.5 + (float)viewSize[1] * s * r);
- ov.visible = (ov.p[0] >= -ov.r && ov.p[0] <= viewSize[0] + ov.r &&
- ov.p[1] >= -ov.r && ov.p[1] <= viewSize[1] + ov.r);
- return ov.visible;
- }
-
- static void findVisibility()
- {
- // FIXME -- fix sticky sizes for explosions (only stick if big and do
- // correct visibility for the sticky size)
- for (int i = 0; i < MAXPLAYERS; i++) {
- ShipObject* s = shipList[i];
- if (!s) continue;
- ShipInfo& si = s->shipInfo();
- if (!self(s)) {
- if (s->active() != ObjectActive) {
- playerView[i][0].visible = FALSE;
- continue;
- }
- myShip->findLocalPosition(si.info.position, playerView[i][0].lp);
- if (si.info.explodeTime == 0.0) {
- computeVisibility(playerView[i][0], s->shipBound());
- playerView[i][0].exploding = FALSE;
- s->shipVisibility(playerView[i][0].visible);
- }
- else {
- short oldSize = playerView[i][0].exploding ? playerView[i][0].r : -1;
- computeVisibility(playerView[i][0], 2.0 * s->shipBound());
- playerView[i][0].exploding = TRUE;
- s->shipVisibility(FALSE);
-
- // make explosion sizes sticky
- if (oldSize != -1) playerView[i][0].r = oldSize;
- }
- }
- else {
- playerView[i][0].visible = FALSE;
- if (s->active() == ObjectInactive) continue;
- }
-
- for (int j = 0; j < MAXMISSILES; j++) {
- if (si.missile[j].active != ObjectActive) continue;
- myShip->findLocalPosition(si.missile[j].position, playerView[i][j+1].lp);
- if (si.missile[j].explodeTime == 0.0) {
- computeVisibility(playerView[i][j+1], s->missileBound());
- playerView[i][j+1].exploding = FALSE;
- s->missileVisibility(j, playerView[i][j+1].visible);
- }
- else {
- short oldSize = playerView[i][j+1].exploding? playerView[i][j+1].r: -1;
- computeVisibility(playerView[i][j+1], 2.5 * s->missileBound());
- playerView[i][j+1].exploding = TRUE;
- s->missileVisibility(j, FALSE);
-
- // make explosion sizes sticky
- if (oldSize != -1) playerView[i][j+1].r = oldSize;
- }
- }
- }
-
- // find asteroid visibility
- for (i = 0; i < numberAsteroids(); i++) {
- myShip->findLocalPosition(asteroidPosition(i), asteroidView[i].lp);
- int v = computeVisibility(asteroidView[i], asteroidRadius(i));
- if (!v) asteroidVisibility(i, -1);
- else if (asteroidView[i].r > 10) asteroidVisibility(i, 0);
- else asteroidVisibility(i, 1);
- }
-
- // find flag visibility
- for (i = 0; i < NUMTEAMS; i++) {
- if (teamStatus[i].state == FlagReady) {
- myShip->findLocalPosition(teamStatus[i].position, flagView[i].lp);
- flagVisibility(Team(i), computeVisibility(flagView[i], 1.75 * FLAGSIZE));
- }
- }
- }
-
- static void forceInventorRedraw()
- {
- // touch camera node so that Inventor redraws
- camera->position = camera->position;
- }
-
- static void reshapeViewScreen()
- {
- viewSize = view->getSize();
-
- // get constants for a particular shape
- cameraCotan = -1.0 / tan(camera->heightAngle.getValue() / 2.0);
- cameraAspect = camera->aspectRatio.getValue();
- }
-
- static double timeDiff(const struct timeval* t2,
- const struct timeval* t1)
- {
- return (double)((long)(t2->tv_sec - t1->tv_sec)) +
- (double)(t2->tv_usec - t1->tv_usec) / 1000000.0;
- }
-
- static void frameAdvance(void*, SoSensor*)
- {
- static float inBaseTime = 0.0;
-
- // get time step between frames
- gettimeofday(&timeEnd, &tz);
- float dt = timeDiff(&timeEnd, &timeStart);
- timeStart = timeEnd;
-
- if (!paused) {
- goingIdle->schedule();
- if (!frameDrawn) return;
- frameDrawn = FALSE;
- frameNumber++;
-
- handleServerMessages();
- handleBroadcastMessages();
-
- // get frames per second every second or every 2 frames (whichever longer)
- if (frameNumber >= 2) {
- float dtFps = timeDiff(&timeEnd, &fpsStart);
- if (dtFps >= 1.0) {
- fpsStart = timeStart;
- fps = int(float(frameNumber) / dtFps + 0.5);
- frameNumber = 0;
- }
- }
-
- // advance my ship in time
- myShip->advance(dt);
- float* p = myShip->shipInfo().info.position;
-
- if (myShip->active() == ObjectActive && !myShip->exploding()) {
-
- // check if I'm on any flags
- if (myShip->flag() == NoTeam) {
- float dx, dy, dz;
- for (int i = 0; i < NUMTEAMS; i++)
- if (teamStatus[i].state == FlagReady) {
- dx = teamStatus[i].position[0] - p[0];
- dy = teamStatus[i].position[1] - p[1];
- dz = teamStatus[i].position[2] - p[2];
- if (dx*dx + dy*dy + dz*dz <=
- (myShip->shipBound()+FLAGSIZE)*(myShip->shipBound()+FLAGSIZE))
- myShip->grabFlag(Team(i));
- }
- }
-
- // check if I'm in a team base
- Team whichBase = insideBase(myShip->shipInfo().info.position,
- myShip->shipBound());
- if (whichBase != NoTeam) {
- Team f = myShip->flag(), t = myShip->team();
- if (f != NoTeam) { // maybe a capture
- if ((whichBase != t && f == t) || // my flag in enemy base
- (whichBase == t && f != t)) { // enemy flag in my base
- SwCaptureFlagMessage m;
- m.flagTeam = f;
- m.captorTeam = t;
- server()->send(m);
- }
- }
- if (whichBase == t) { // in my base, resupply me
- inBaseTime += dt;
-
- // increase missiles
- int s = int(inBaseTime);
- inBaseTime -= float(s);
- if (s > 0 && myShip->numMissiles() < myShip->maxMissiles()) {
- myShip->numMissiles(myShip->numMissiles() + s);
- missileChanged();
- }
-
- // increase fuel
- if (myShip->fuelLeft() < 1.0) {
- myShip->fuelLeft(myShip->fuelLeft() + 0.5*dt*myShip->fuelRate());
- fuelChanged();
- }
-
- // increase shields
- myShip->shieldStrength(0.01*dt);
- shieldsChanged();
- }
- }
- else inBaseTime = 0.0;
-
- // see if I hit an asteroid
- int a = hitAsteroid(p, myShip->shipBound());
- if (a != -1) {
- // move me outside of asteroid and make me stationary
- float* ap = asteroidPosition(a);
- SbVec3f sp(p[0] - ap[0], p[1] - ap[1], p[2] - ap[2]);
- sp.normalize();
- sp *= myShip->shipBound() + asteroidRadius(a);
- sp += SbVec3f(ap);
- myShip->position(sp);
- myShip->velocity(SbVec3f(0.0, 0.0, 0.0));
-
- // blow me up
- myShip->shipInfo().lost++;
- myShip->explodeShip(NetId());
- server()->send("hit an asteroid");
- }
-
- }
-
- // broadcast my ship's data
- sendBroadcast(myShip->shipInfo());
-
- // find available targets
- findTargets();
-
- // advance things in the universe
- universeAdvance(dt);
-
- // find visibility state for all active objects
- findVisibility();
-
- // move missile lock box towards target if:
- // missiles are the selected weapon
- // a missile is ready
- // a target is selected
- // target is not exploding
- // and target is on screen
- if (target != -1 && weaponState == Missile &&
- playerView[targetPlayer[target]][0].visible &&
- !playerView[targetPlayer[target]][0].exploding &&
- myShip->missileReady()) {
- ObjectView& o = playerView[targetPlayer[target]][0];
- float dx = float((o.p[0] - (viewSize[0]>>1)) - missileLock.p[0]),
- dy = float((o.p[1] - (viewSize[1]>>1)) - missileLock.p[1]);
- float d = sqrt(dx * dx + dy * dy);
- if (d < dt*250.0) {
- missileLock.p[0] = o.p[0] - (viewSize[0]>>1);
- missileLock.p[1] = o.p[1] - (viewSize[1]>>1);
- if (missileLock.r != 16) {
- missileLock.r = 16;
- soundPlay(LockOnSound);
- }
- }
- else {
- missileLock.p[0] = short(missileLock.p[0] + dx*dt*250.0/d);
- missileLock.p[1] = short(missileLock.p[1] + dy*dt*250.0/d);
- missileLock.r = 8;
- soundPlay(SeekingSound);
- }
- missileLock.visible = TRUE;
- }
- else {
- missileLock.visible = FALSE;
- missileLock.r = 0;
- }
-
- // show radar and whatever else needs to be drawn in the control panel
- controlPanelAdvance(dt);
-
- // advance sound (play it)
- soundAdvance(dt);
-
- // make inventor show next frame even if nothing changed
- forceInventorRedraw();
- }
- }
-
- static void prepareForFirstFrame()
- {
- // for frameAdvance() will get called
- goingIdle->schedule();
-
- // skip any time we've been asleep
- gettimeofday(&timeStart, &tz);
- fpsStart = timeStart;
- fps = 0;
-
- // reset frame count
- frameNumber = 0;
- frameDrawn = FALSE;
-
- // make Inventor show frame
- forceInventorRedraw();
- }
-
- static int handleGlobalEvents(XEvent* e)
- {
- switch (e->xany.type) {
- case KeyPress:
- case KeyRelease:
- return keyEvent(e);
- case ButtonPress:
- case ButtonRelease: {
- int b;
- switch (e->xbutton.button) {
- case Button1:
- b = LeftMouseButton;
- break;
- case Button2:
- b = MiddleMouseButton;
- break;
- case Button3:
- b = RightMouseButton;
- break;
- }
- buttonPressed[b] = (e->xany.type == ButtonPress);
- break; // allow others to use event
- }
- }
- return FALSE;
- }
-
- static void usage(const char* pname)
- {
- cerr << "usage: " << pname << " -n callsign -s server teamname\n";
- cerr << "\tteamname may be r, g, b, or p.\n";
- exit(1);
- }
-
- static char* callsign = NULL;
- static char* serverName = NULL;
- static Team myTeam = NoTeam;
-
- static void parse(int argc, char** argv)
- {
- for (int i = 1; i < argc; i++) {
- if (argv[i][0] == '-') switch(argv[i][1]) {
- case 'n':
- if (callsign) usage(argv[0]);
- callsign = argv[++i];
- break;
- case 's':
- if (serverName) usage(argv[0]);
- serverName = argv[++i];
- break;
- default:
- usage(argv[0]);
- }
- else {
- switch (argv[i][0]) {
- case 'r':
- case 'R':
- myTeam = RedTeam;
- break;
- case 'g':
- case 'G':
- myTeam = GreenTeam;
- break;
- case 'b':
- case 'B':
- myTeam = BlueTeam;
- break;
- case 'p':
- case 'P':
- myTeam = PurpleTeam;
- break;
- default:
- usage(argv[0]);
- }
- }
- }
- if (myTeam == NoTeam) usage(argv[0]);
- if (!callsign || !serverName) usage(argv[0]);
- }
-
- int main(int argc, char** argv)
- {
- int i;
-
- // initialize random number generator
- srand48(time(NULL));
-
- parse(argc, argv);
-
- // make server connection object
- gameServer = new SwServer(serverName);
- if (gameServer->state() != SwServer::NotConnected) {
- cerr << "can't connect to server\n";
- return 1;
- }
-
- // open broadcast socket
- if (!openBroadcast(BROADCASTPORT)) {
- cerr << "can't open broadcast port\n";
- return 1;
- }
-
- makeDisplay(argv[0]); // make render areas
- // FIXME -- make sure makeDisplay() worked
-
- // make universe (sun, stars, places for ships, etc.)
- makeUniverse();
-
- // we have some callbacks in the graph and Inventor doesn't seem to
- // like to cache bounding boxes when they're there.
- universe->setBoundingBoxCaching(FALSE);
-
- // view universe (with transparent things correctly)
- view->setSceneGraph(universe);
- view->setTransparencyType(SoGLRenderAction::DELAYED_ADD);
-
- // create head's up display
- makeHud();
-
- // set sensor to fire whenever Inventor is done with it's stuff
- goingIdle = new SoOneShotSensor(frameAdvance, NULL);
-
- // read explosion data
- if (!readExplosion(explosionDirectory())) {
- cerr << "can't read explosion movie\n";
- return 1; // quit with error code
- }
-
- // open audio port
- openSound(soundsDirectory());
-
- // initialize global info
- for (i = 0; i < NUMTEAMS; i++) { // initialize teams
- teamStatus[i].team = Team(i);
- teamStatus[i].players = 0;
- teamStatus[i].won = 0;
- teamStatus[i].lost = 0;
- teamStatus[i].state = FlagNoExist;
- }
- numPlayers = 0;
- for (i = 0; i < MAXPLAYERS; i++) shipList[i] = NULL;
- numTargets = 0;
- target = -1;
- for (i = 0; i < MAXPLAYERS; i++) targetList[i] = NULL;
- rangeState = 1;
- weaponState = Laser;
- wasFlagCaptured = TRUE; // start me in my base
- missileLock.visible = FALSE;
- missileLock.p[0] = 0;
- missileLock.p[1] = 0;
-
- // make my ship and add it to universe
- myShip = new RegularShip(server()->hostId(), myTeam, callsign);
- initializeSelf();
- myShip->active(ObjectInactive);
- addPlayer(myShip);
- wasFlagCaptured = TRUE; // start me in my base again
-
- // connect to server
- if (!server()->open(myShip)) {
- cerr << "cannot connect to server\n";
- return 1; // quit with error code
- }
-
- // realize everything and display the window
- SoXt::show(mainWindow);
- reshapeViewScreen();
-
- // reset various stuff (after window open cos they might draw stuff)
- hudReset();
- controlPanelReset();
-
- // tell everyone we're here
- server()->send("joining as a ship");
-
- // no mouse buttons down
- for (i = int(LeftMouseButton); i <= int(RightMouseButton); i++)
- buttonPressed[i] = FALSE;
-
- if (hasSound()) soundDial(SoundAll);
-
- prepareForFirstFrame();
-
- // Main event loop
- // Get event and dispatch it. Also check for events we're always
- // interested in knowing about. This includes keyboard events because
- // the keyboard has the same effect everywhere.
- // It's a good thing we don't need to pass extension events to Inventor!
- XEvent event;
- XtAppContext context = SoXt::getAppContext();
- while (!done) {
- if (server()->state() != SwServer::Connected) {
- cerr << "unexpected loss of server connection -- terminating\n";
- break; // lost my server connection
- }
-
- XtAppNextEvent(context, &event);
- if (!handleGlobalEvents(&event)) // see if I want it
- XtDispatchEvent(&event); // dispatch it if I don't
-
- // check for window resizing
- if (event.xany.type == ConfigureNotify) {
- XConfigureEvent* ce = (XConfigureEvent*)&event;
- if (ce->window == XtWindow(view->getWidget()) &&
- ce->width != viewSize[0] || ce->height != viewSize[1])
- reshapeViewScreen();
- }
-
- // check for window mapping (un-iconfiy falls in this category)
- else if (event.xany.type == MapNotify &&
- event.xmap.window == XtWindow(mainWindow)) {
- if (pausedOnIconify) {
- pausedOnIconify = FALSE;
- resumeGame();
- }
- frameDrawn = FALSE;
- frameNumber++;
- forceInventorRedraw();
- }
-
- // check for window unmapping (iconfiy falls in this category)
- else if (event.xany.type == UnmapNotify &&
- event.xunmap.window == XtWindow(mainWindow)) {
- if (!paused) {
- pausedOnIconify = TRUE;
- pauseGame();
- }
- }
- }
-
- // drop any flag I have
- myShip->dropFlag();
-
- // tell everyone we're leaving
- server()->send("signing off");
-
- // close server connection
- delete gameServer;
-
- // close broadcast connection
- closeBroadcast();
-
- // close audio port
- closeSound();
-
- // delete all the players
- for (i = 0; i < MAXPLAYERS; i++)
- delete removePlayer(i);
-
- // delete other stuff
- deleteUniverse();
-
- return 0;
- }
-
- int self(const ShipObject* o)
- {
- return (o->id() == myShip->id());
- }
-
- int self(InAddr a)
- {
- return (NetId(a) == myShip->id());
- }
-
- int self(NetId id)
- {
- return (id == myShip->id());
- }
-
- void restartSelf()
- {
- initializeSelf();
- controlPanelReset();
- SwAliveMessage m;
- server()->send(m);
- }
-
- SwServer* server()
- {
- return gameServer;
- }
-
- int numberPlayers()
- {
- return numPlayers;
- }
-
- ShipObject* getPlayer(int i)
- {
- if (i < 0 || i >= MAXPLAYERS) return NULL;
- return shipList[i];
- }
-
- int addPlayer(ShipObject* s)
- {
- if (numPlayers >= MAXPLAYERS) return FALSE; // no room!
- for (int i = 0; i < MAXPLAYERS; i++) // scan list
- if (shipList[i] == NULL) { // for an empty slot
- shipList[i] = s; // fill it in
- numPlayers++; // one more player
- ships->insertChild(s->root(), 0); // add ship to scene graph
- playersChanged(); // show new player count
- return TRUE; // successful add
- }
- return FALSE;
- }
-
- ShipObject* removePlayer(int num)
- {
- ShipObject* s = shipList[num];
- if (s == NULL) return s; // no such player
- ships->removeChild(s->root()); // remove from scene graph
- shipList[num] = NULL; // make slot empty
- numPlayers--; // one less player
- return s; // successful remove
- }
-
- int lookupPlayer(NetId id)
- {
- for (int i = 0; i < MAXPLAYERS; i++) // search all slots
- if (shipList[i] && shipList[i]->id() == id) // if id's match
- return i; // found it
- return -1; // didn't find it
- }
-
- TeamInfo& getTeam(Team t)
- {
- return teamStatus[int(t)];
- }
-
- void setTeam(const TeamInfo& info)
- {
- Team t = info.team;
- TeamInfo& ti = teamStatus[int(t)];
- int oldState = ti.state;
- ti = info;
- switch (ti.state) {
- case FlagNoExist: // flag is gone now
- if (oldState != ti.state)
- flagInSpace(t, FALSE);
- if (t == myShip->flag()) { // I used to have it
- myShip->flag(NoTeam); // I have nothing now
- flagChanged();
- }
- break;
- case FlagReady:
- if (oldState != ti.state)
- flagInSpace(t, TRUE);
- break;
- case FlagOnShip:
- if (oldState != ti.state)
- flagInSpace(t, FALSE);
- break;
- }
- }
-
- int numberTargets()
- {
- return numTargets;
- }
-
- int currentTarget()
- {
- return target;
- }
-
- ShipObject* getTarget(int t)
- {
- return targetList[t];
- }
-
- void nextTarget()
- {
- if (numTargets == 0) return;
- if (++target >= numTargets) target = -1;
- targetChanged();
- }
-
- void prevTarget()
- {
- if (numTargets == 0) return;
- if (--target < -1) target = numTargets - 1;
- targetChanged();
- }
-
- void noTarget()
- {
- if (target == -1) return;
- target = -1;
- targetChanged();
- }
-
- float radarRange()
- {
- return range[rangeState];
- }
-
- void increaseRange()
- {
- if (rangeState >= NUMRADARRANGES-1) return;
- rangeState++;
- }
-
- void decreaseRange()
- {
- if (rangeState < 1) return;
- rangeState--;
- }
-
- Weapon currentWeapon()
- {
- return weaponState;
- }
-
- void currentWeapon(Weapon w)
- {
- if (weaponState != w) {
- weaponState = w;
- weaponChanged();
- }
- }
-
- void toggleFps()
- {
- showFps = !showFps;
- }
-
- int isFpsOn()
- {
- return showFps;
- }
-
- int getFps()
- {
- return fps;
- }
-
- SbVec2s& viewScreenSize()
- {
- return viewSize;
- }
-
- void getViewDirection(const SbVec2s& p, SbVec3f& v)
- {
- float x = (float)p[0] / (float)viewSize[0] * 2.0 - 1.0,
- y = (float)p[1] / (float)viewSize[1] * 2.0 - 1.0,
- z = cameraCotan;
- v.setValue(x * cameraAspect, y, z);
- v.normalize();
- }
-
- int getViewPosition(const SbVec3f& v, SbVec2s& p)
- {
- if (v[2] != 0.0) {
- float t = 0.5 * cameraCotan / v[2];
- p[0] = (short)(0.5 + (float)viewSize[0] * (t * v[0] / cameraAspect + 0.5));
- p[1] = (short)(0.5 + (float)viewSize[1] * (t * v[1] + 0.5));
- return (t > 0.0);
- }
- else {
- p[0] = p[1] = 0;
- return FALSE;
- }
- }
-
- void showHelp()
- {
- char buf[256];
- sprintf(buf, "/usr/sbin/showcase -v %s", helpFile());
- pauseGame();
- system(buf);
- }
-
- void pauseGame()
- {
- if (!paused) togglePauseGame();
- }
-
- void resumeGame()
- {
- if (paused) togglePauseGame();
- }
-
- void togglePauseGame()
- {
- paused = !paused;
-
- if (paused) {
- // tell everyone we've paused
- server()->send("Paused");
-
- // we want to send our data every second to let people know we're here
- pausedTimeout = XtAppAddTimeOut(SoXt::getAppContext(), 1000,
- pausedWakeup, 0);
-
- oldActive = myShip->active();
- myShip->active(ObjectPaused);
- // send my data every second or so while I'm paused
- }
- else {
- // tell everyone we've resumed
- server()->send("Resumed");
-
- XtRemoveTimeOut(pausedTimeout);
- prepareForFirstFrame();
- handleServerMessages();
- handleBroadcastMessages();
- // flush radio buffers here
- myShip->active(oldActive);
- }
- }
-
- int isPaused()
- {
- return paused;
- }
-
- void quitGame()
- {
- done = TRUE;
- }
-
- ShipObject* makeShip(ShipClass c, NetId id, Team t, const char* n)
- {
- switch (c) {
- case ShipClassRegular:
- return new RegularShip(id, t, n);
- }
- return 0;
- }
-
- float explodeVolume(float p[3], float v)
- {
- float* o = myShip->shipInfo().info.position;
- float dx = o[0] - p[0],
- dy = o[1] - p[1],
- dz = o[2] - p[2];
- float d = (dx * dx + dy * dy + dz * dz);
- if (d <= BASERADIUS * BASERADIUS) return 1.0;
- d = v * BASERADIUS / sqrt(d);
- if (d > 1.0) return 1.0;
- return d;
- }
-